import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.codahale.shamir.*;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;

/*
 * @Author: Wang Feng
 * @Description: A implementation of Shamir's Secret Sharing algorithm over GF(256).
 *      基于maven库实现：https://www.npmjs.com/package/shamir
 *
 * @Version: 1.0.0
 * @Date: 11:04 2021/5/6
 * @Copyright: MIN-Group；国家重大科技基础设施——未来网络北大实验室；深圳市信息论与未来网络重点实验室
 */
public class MIN_SSS {

    /**
     * 测试SSS算法库是否可用
     */
    public static void testSSS_Java(){
        // n=5, k=3。 表示一份密钥可以分成五份密钥切片，每三份都可以合成原密钥。
        final Scheme scheme = new Scheme(new SecureRandom(), 5, 3);
        final byte[] secret = "MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgPbk7uX+BhJALxTTzDUAqk1/6+WBletfw69Yf7rf3Fz+gCgYIKoEcz1UBgi2hRANCAARcf6564lLpwHQrLq7S5KIalJTP3MYsLEavUzCagCb14esWIaj0cfek9m7OdCtcdyXSRdovdQbLMBHFoV7D4rMb".getBytes(StandardCharsets.UTF_8);
        Map<Integer, byte[]> parts = scheme.split(secret);

        // 由于parts是不可更改的，故此这里新建了一个map去测试sss算法
        System.out.println("n=5,k=3");
        Map<Integer, byte[]> newParts=new HashMap<>();
        for (int i = 1; i <= 5; i++) {
            newParts.put(i,parts.get(i));
        }

        // 输出parts信息
        System.out.println("总个数: "+newParts.size());
        for (int i = 1; i <= 5; i++) {
            System.out.println("分钥"+i+": "+Arrays.toString(newParts.get(i)));
        }
        byte[] recovered = scheme.join(newParts);
        System.out.println("原密钥: "+new String(recovered, StandardCharsets.UTF_8));

        // 逐个去掉分密钥，然后看合并的结果
        for (int i = 1; i <= 4; i++) {
            System.out.println("************去掉"+i+"个分钥***********");
            newParts.remove(i);
            System.out.println("还剩下分钥个数: "+newParts.size());
            recovered = scheme.join(newParts);
            System.out.println("恢复出来的原密钥: "+new String(recovered, StandardCharsets.UTF_8));
            System.out.println("****************************************");
        }
    }

    /**
     * 测试Go语言中的SSS算法是否与Java中的SSS算法兼容
     * @throws DecoderException
     */
    public static void testGo() throws DecoderException {
        String sec="MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgPbk7uX+BhJALxTTzDUAqk1/6+WBletfw69Yf7rf3Fz+gCgYIKoEcz1UBgi2hRANCAARcf6564lLpwHQrLq7S5KIalJTP3MYsLEavUzCagCb14esWIaj0cfek9m7OdCtcdyXSRdovdQbLMBHFoV7D4rMb";
        final Scheme scheme = new Scheme(new SecureRandom(), 3, 2);
        Map<Integer,byte[]> parts=new HashMap<>();
        String s1="56cc5b50b6a4f74ce0e19ccd8d55f8a703bdf904a0b99563f229152956e7b2d9c9f95f78b1f2aa793d3fd32e2128ab9878cc76191e2734a45b5f0e4613276059660a95c41ace3d94d4be093b14646cd2998c9e99ec07c2110d4ef3e4bd3e14d89858c3685c385497a31deb169b3accc5b52ed517d9d02d4467b196851f3786095f3389ca468753fac86629d69948557917258c48fc26802c40852aaf71a843851985565b3425d58ff3dbd0aae8f30d92bffa3bc01394afe4b2c1e9f0e725338b098d54edb0c043dd";
        String s2="7b587f5cb4fa3a5b0c1ff448c721789cf3b6b54398c0fe0f3a97b994740234534a02656cbf27f26bd6e7669a81a3be820025516ba3a615950e60df58aeb23c3c00ebf20089d40b69ce9ed4c2875472267348cc839a983577d012807aa4d5c370f6015275362357f3f4819b94dbb75154b29f478b03e105d292cde381a7b6e4846af5507ad3c87d4c3f12ae477c474167fa85a00a1cc2defb29d4f216bee413e8e9b212e6cde01eb8b61ae29e6738869ac9649e6ed09ff449d36a6f2f028cbec7a3fbf10d270d5107";
        String s3="60dd635843398856a1bc25c2080df17ca346787e791e2e2b8bfdddff6aa8bfdcc2a273604c9d33658faffcf6e1da447d288b4c45c8d90a733d759052c5c1081f22b426b5f82b19cb31779f95f6447883dcfd0b7c41ed91559b2658f95a8c8ee12536d47e102a562630f542ea12ccd3d246f0c0ffbc071da0c1103974cfc933ff79b7eee3a00467d79b3ed3c1d6424d6da1e54d34b59e1db60e12ba88fb29233ab9562e8d9aa3ae5c7cac057beb88ff6b12e7fdfd916f34db05fae493a8ebc50ac52092a4a3bf5fb8";
        byte[] b1= Hex.decodeHex(s1);
        byte[] b2= Hex.decodeHex(s2);
        byte[] b3= Hex.decodeHex(s3);

        parts.put(1,b1);
        parts.put(2,b2);
        parts.put(3,b3);
        byte[] recover=scheme.join(parts);
        String newSec=new String(recover,StandardCharsets.UTF_8);
        System.out.println(newSec);
        System.out.println("Go语言中的SSS算法与Java中的SSS算法是否兼容："+sec.equals(newSec));
    }

    // 暂时没有要求封装。下面是SSS库测试代码。
    public static void main(String[] args){
        testSSS_Java();
        try {
            testGo();
        } catch (DecoderException e) {
            e.printStackTrace();
        }
    }
}
